package cn.xy.base.server.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.crypto.SecureUtil;
import cn.xy.base.server.config.AppConfig;
import cn.xy.base.server.config.OSSConfig;
import cn.xy.base.server.po.SysAttachment;
import cn.xy.base.server.service.SysAttachmentService;
import cn.xy.base.server.service.UploadService;
import cn.xy.base.server.utils.ImgTypeUtil;
import cn.xy.commons.constant.Consts;
import cn.xy.commons.exception.JzRuntimeException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

/**
 * 本地上传
 *
 *  @author xy
 */
@Slf4j
@Service("uploadService")
public class UploadServiceImpl implements UploadService {

    @Autowired
    private AppConfig appConfig;

    @Autowired
    private OSSConfig ossConfig;

    @Autowired
    private SysAttachmentService sysAttachmentService;

    private static final String ERROR_MSG = "文件上传出错=>";

    @Override
    public String upload(MultipartFile file) {
        return this.upload(file, ossConfig.getPath(), false);
    }

    @Override
    public String upload(MultipartFile file, String basePath, boolean generateCompress) {
        try {
            return this.upload(file.getInputStream(), file.getOriginalFilename(), basePath, false);
        } catch (IOException e) {
            log.error(ERROR_MSG, e);
            throw new JzRuntimeException("文件上传异常");
        }
    }

    @Override
    public String upload(InputStream inputStream, String filename) {
        return this.upload(inputStream, filename, ossConfig.getPath(), false);
    }

    @Override
    public String upload(InputStream inputStream, String filename, String basePath, boolean generateCompress) {
        byte[] fileBytes = IoUtil.readBytes(inputStream);
        try (ByteArrayInputStream fileInputStream = new ByteArrayInputStream(fileBytes)) {
            String sha1 = SecureUtil.sha1(fileInputStream);
            SysAttachment attachment = sysAttachmentService.getBySha1(sha1);
            if (attachment != null) {
                return attachment.getUrlPath();
            }

            String suffix = FileUtil.extName(filename);
            String filePrefix = UUID.randomUUID().toString();
            String newFileName = filePrefix + Consts.DOT + suffix;
            String thumbFileName = filePrefix + "_thumb." + suffix;
            String relativeBasePath;
            if (CharSequenceUtil.isEmpty(basePath)) {
                relativeBasePath = "";
            } else {
                relativeBasePath = basePath;
            }
            String datePrefix = DateUtil.format(DateUtil.date(), "yyyy-MM");
            relativeBasePath += Consts.SLASH + datePrefix;

            File dir = FileUtil.file(appConfig.getUploadBasePath(), relativeBasePath);
            if (!dir.exists()) {
                log.debug("baseDir create:{}", dir.getAbsoluteFile());
                FileUtil.mkdir(relativeBasePath);
            }
            File outFile = FileUtil.file(appConfig.getUploadBasePath(), relativeBasePath + Consts.SLASH + newFileName);
            log.debug("outFile:{}", outFile.getAbsoluteFile());

            // 保存图片
            inputStream = new ByteArrayInputStream(fileBytes);
            FileUtil.writeFromStream(inputStream, outFile);
            // 缩略图生成
            String compressPath = "";
            if (generateCompress) {
                inputStream = new ByteArrayInputStream(fileBytes);
                String type = FileTypeUtil.getType(inputStream);
                if (ImgTypeUtil.isImage(type)) {
                    String url = appConfig.getUploadBasePath() + Consts.SLASH + relativeBasePath + Consts.SLASH + thumbFileName;
                    inputStream = new ByteArrayInputStream(fileBytes);
                    Image compress = this.generateCompress(inputStream);
                    if (compress != null) {
                        ImgUtil.write(compress, FileUtil.file(url));
                    }
                }
            }
            // 保存上传记录
            String fileUrl = relativeBasePath + Consts.SLASH + newFileName;
            attachment = new SysAttachment();
            attachment.setSha1(sha1);
            attachment.setPath(outFile.getAbsolutePath());
            attachment.setUrlPath(fileUrl);
            attachment.setCompressPath(compressPath);
            attachment.setCreateTime(DateUtil.date());
            attachment.setName(filename);
            sysAttachmentService.save(attachment);
            return fileUrl;
        } catch (Exception e) {
            log.error(ERROR_MSG, e);
        } finally {
            try {
                inputStream.close();
            } catch (Exception e) {
                log.error(ERROR_MSG, e);
            }
        }
        throw new JzRuntimeException("文件上传异常");
    }

    @Override
    public Image generateCompress(InputStream inputStream) {
        int scaleWeight = 300;
        try {
            // 生成图片
            BufferedImage image = ImgUtil.read(inputStream);
            // 图片尺寸过小时不再缩略
            if (image.getWidth() <= scaleWeight) {
                return image;
            }
            int scaleHeight = image.getHeight() / (image.getWidth() / scaleWeight);
            return ImgUtil.scale(image, scaleWeight, scaleHeight);
        } catch (Exception e) {
            log.error("压缩图片/缩略图片生成失败=> {}", e.getMessage());
        }
        return null;
    }

    @Override
    public byte[] getByteByUrl(String url) {
        if (url == null) {
            return new byte[0];
        }
        String path = appConfig.getUploadBasePath() + Consts.SLASH + url;
        return FileUtil.readBytes(path);
    }

    @Override
    public SysAttachment getSysAttachmentByUrl(String url) {
        return sysAttachmentService.getOne(new LambdaQueryWrapper<SysAttachment>().eq(SysAttachment::getUrlPath, url));
    }

}
